// vi:si:et:sw=4:sts=4:ts=4
package cat.hex.trainoid;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

public class Map extends MapActivity
{
	protected static MapView mapView;
	protected static MapController mc;
	protected static Location myCurrentLocation;

	protected DbAdapter mDbHelper;

	static final private String tag = "map"; // for Log

	protected static final int DEFAULT_ZOOM_LEVEL = 14;

	private static final int GPS_ID = Menu.FIRST;
	private static final int CURRENT_POSITION_ID = Menu.FIRST + 1;
	private static final int TOGGLE_LAYER_ID = Menu.FIRST + 2;
	private static final int TOGGLE_RECORDING_ID = Menu.FIRST + 3;
	//private static final int SAVE_TRACK = Menu.FIRST + 4;

	// private static final int ACTIVITY_MAP=0;
	// private static final int ACTIVITY_GPS=1;

	//private trainoid mtrainoid;
	private static GPSReceiver service;
	private MyLocationOverlay meOverlay;

	@Override
	public void onResume()
	{
		super.onResume();

		meOverlay.enableCompass();
		meOverlay.enableMyLocation();
	}

	@Override
	protected void onPause()
	{
		super.onResume();

		meOverlay.disableMyLocation();
		meOverlay.disableCompass();
	}

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);

		MapOverlay mapOverlay;
		long mTrackId = -1;
		// registerForContextMenu(getListView());

		setContentView(R.layout.map);

		initializeData();
		service = GPSReceiver.getInstance();

		if (!service.isMapCreated())
		{
			service.setMap(this);

			showCurrentPosition(true);
			zoomMap(DEFAULT_ZOOM_LEVEL);
		}

		Bundle extras = getIntent().getExtras();
		mTrackId = (long)extras.getLong("mTrackId");


		if (mTrackId > 0)
		{
			Track mTrack = new Track(mTrackId, this);

			mTrack.centerMap(mc);
			//GeoPoint center = mTrack.getGeoCenter();
			//mc.animateTo(center);
			//mc.zoomToSpan(Math.abs( minLat - maxLat ), Math.abs( minLong - maxLong ));

			mapOverlay = new MapOverlay(mTrackId, mapView, this);
		}	
		else
		{
			mapOverlay = new MapOverlay(service.getPath(), mapView, this);
		}


		List<Overlay> listOfOverlays = mapView.getOverlays();

		listOfOverlays.clear();
		listOfOverlays.add(mapOverlay);

		if (service.isFollowing() == true)
			addMeOverlay();

		refresh();
	}

	protected void initializeData()
	{
		mapView = (MapView) findViewById(R.id.mapview);
		mapView.setBuiltInZoomControls(true);

		// for show 'my' position on the map
		meOverlay = new MyLocationOverlay(this, mapView);

		mc = mapView.getController();

		myCurrentLocation = getCurrentLocation(false);
	}

	public void refresh()
	{
		if (mapView != null)
			mapView.invalidate();
	}

	@Override
	protected boolean isRouteDisplayed()
	{
		return true;
	}

	/**
	 * Toggles between satellite and map view layer.
	 */
	public void toggleLayer()
	{
		mapView.setSatellite(!mapView.isSatellite());
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		super.onCreateOptionsMenu(menu);

		if (service.isRecording() == true)
			menu.add(0, TOGGLE_RECORDING_ID, 0, R.string.menu_stop_recording);
		else
			menu.add(0, TOGGLE_RECORDING_ID, 0, R.string.menu_start_recording);

		menu.add(0, CURRENT_POSITION_ID, 0, R.string.menu_show_current_position);
		menu.add(0, TOGGLE_LAYER_ID, 0, R.string.menu_toggle_layer);

		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item)
	{
		switch (item.getItemId())
		{
			case TOGGLE_RECORDING_ID:
				toggleRecording();
				return true;
			case CURRENT_POSITION_ID:
				showCurrentPosition(true);
				return true;
			case TOGGLE_LAYER_ID:
				toggleLayer();
				return true;
		}

		return super.onMenuItemSelected(featureId, item);
	}

	/**
	 * showGPS function launches the GPS positions list.
	 */
	private void toggleRecording()
	{
		if (service.isRecording() == false)
			startRecording();
		else
			stopRecording();
	}

	protected void stopRecording()
	{
		service.stopRecording();
	}

	protected void startRecording()
	{
		service.startRecording();
	}

	/**
	 * showCurrentPosition center the current location into the map.
	 *
	 * @param showText
	 *            this parameter defines if some text will be shown or not.
	 */
	protected void showCurrentPosition(boolean showText)
	{
		myCurrentLocation = getCurrentLocation(showText);
		if (myCurrentLocation != null)
		{
			GeoPoint point = new GeoPoint((int) (myCurrentLocation.getLatitude() * 1e6), (int) (myCurrentLocation.getLongitude() * 1e6));
			mc.animateTo(point);

			service.setFollowing(!service.isFollowing());
		}
		else
		{
			service.setFollowing(!service.isFollowing());
			if (showText == true) Toast.makeText(this, getString(R.string.status_no_location), Toast.LENGTH_LONG).show();
		}

		addMeOverlay();
	}

	protected void addMeOverlay()
	{
		if (service.isFollowing() == true)
		{
			meOverlay.enableMyLocation();
			meOverlay.enableCompass();

			mapView.getOverlays().add(meOverlay);
		}
	}

	/**
	 * Makes a zoom to the indicated level.
	 *
	 * @param zoomLevel
	 *            defines the level of the zoom.
	 */
	public void zoomMap(int zoomLevel)
	{
		mc.setZoom(zoomLevel);
	}

	/**
	 * getCurrentLocation tries to get the Location from the most accurate
	 * position from GPS or WiFi antennas.
	 *
	 * @param showText
	 *            this parameter defines if some text will be shown or not.
	 */
	public Location getCurrentLocation(boolean showText)
	{
		LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		if (locationManager == null) return null;

		final long maxAgeMilliSeconds = 1000 * 60 * 1; // 1 minute
		final long maxAgeNetworkMilliSeconds = 1000 * 60 * 10; // 10 minutes
		final long now = System.currentTimeMillis();

		Location loc = locationManager.getLastKnownLocation("gps");
		if (loc == null || loc.getTime() < now - maxAgeMilliSeconds)
		{
			// We can't get a recent GPS fix, we use cell towers if available
			loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			if (loc == null || loc.getTime() < now - maxAgeNetworkMilliSeconds)
			{
				// We can't get a recent cell tower location
				if (showText == true)
					Toast.makeText(this, getString(R.string.status_no_location), Toast.LENGTH_LONG).show();
				return null;
			}
			else
			{
				// We can have only an approximate location
				if (showText == true) Toast.makeText(this, getString(R.string.status_approximate_location),
						Toast.LENGTH_LONG).show();
			}
		}

		return loc;
	}
}

class MapOverlay extends com.google.android.maps.Overlay
{
	protected static Track mTrack;
    protected Context mCtx;
    protected MapView mMapView;

//	protected int mZoomLevel = -1;
//    protected ArrayList<Point> mPointPath; = new ArrayList<Point>();

    //protected trainoid mtrainoid;
    protected ArrayList<Location> mPath;
	protected int mPathOrigin = -1; // 1: parameter path (recording track); 2: saved track

    protected static GPSReceiver service;

    private final static String tag = "MapOverlay";

    public MapOverlay(ArrayList<Location> newpath, MapView mv, Context ctx)
    {
		mPathOrigin = 1;
		service = GPSReceiver.getInstance();

        mCtx = ctx;
        mMapView = mv;

//		mPath = (ArrayList<Location>) newpath.clone();
        mPath = newpath;
    }

    public MapOverlay(long trackId, MapView mv, Context ctx)
    {
		mPathOrigin = 2;

        Track mTrack = new Track(trackId, ctx);
        mCtx = ctx;
        mMapView = mv;
        mPath = mTrack.getPath();
    }

    @Override
    public boolean draw(Canvas canvas, MapView mv, boolean shadow, long when)
    {
        /* Look for life cycle about overlay, maybe the line belo is not required */
        if (mPathOrigin == 1)
			if (service.isRecording() == true)
				mPath = service.getPath();

		/*
		if (mZoomLevel != mMapView.getZoomLevel())
		{
			mZoomLevel = mMapView.getZoomLevel();
			mPointPath.clear();
		}
		*/

        super.draw(canvas, mv, shadow);
        drawPath(mv, canvas);


        return false;
    }

    public void drawPath(MapView mv, Canvas canvas)
    {
        int x1 = -1, y1 = -1, x2 = -1, y2 = -1;

        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setStrokeWidth(8);
        paint.setAntiAlias(true);
        //paint.setShadowLayer(5, 2, 2, Color.WHITE);


        Paint base = new Paint();
        base.setColor(Color.WHITE);
        base.setStyle(Paint.Style.FILL_AND_STROKE);
        base.setStrokeWidth(14);
        base.setAntiAlias(true);

        Point point;
        GeoPoint geoPoint;

        /*Log.d(tag, "********* drawPath ********** mTrack.getTrackSize(): " + mTrack.getTrackSize() + " mTrack.getTrackId(): " + mTrack.getTrackId());*/
        Log.d(tag, "********* drawPath ********** mPath.size(): " + mPath.size());
        for (int i = 0; i < mPath.size(); i+=2)
        {
            point = new Point();
            geoPoint = new GeoPoint((int)(mPath.get(i).getLatitude()*1e6), (int)(mPath.get(i).getLongitude()*1e6));
			
            mv.getProjection().toPixels(geoPoint, point);

            x2 = point.x;
            y2 = point.y;

            if (i > 0)
			{
            	canvas.drawLine(x1, y1, x2, y2, base);
            	canvas.drawLine(x1, y1, x2, y2, paint);
			}

            x1 = x2;
            y1 = y2;
        }
    }
}

/*
class MeOverlay extends com.google.android.maps.Overlay
{
    protected Context mCtx;
    protected static GPSReceiver service = GPSReceiver.getInstance();

    public MeOverlay(MapView mv, Context ctx)
    {
        mCtx = ctx;
    }

    @Override
    public boolean draw(Canvas canvas, MapView mv, boolean shadow, long when)
    {
        super.draw(canvas, mv, shadow);
        drawMe(mv, canvas);

        return false;
    }

    public boolean drawMe(MapView mv, Canvas canvas)
    {
		if (service.myCurrentLocation != null) {
			Paint paint = new Paint();

			// Converts lat/lng-Point to OUR coordinates on the screen.
			Point myScreenCoords = new Point();
			GeoPoint p = new GeoPoint((int) (service.getCurrentLocation().getLatitude() * 1e6), (int) (service.getCurrentLocation().getLongitude() * 1e6));
			mv.getProjection().toPixels(p, myScreenCoords);
			
			// paint.setStrokeWidth(1);
			// paint.setARGB(255, 255, 255, 255);
			// paint.setStyle(Paint.Style.STROKE);
			
			Bitmap bmp = BitmapFactory.decodeResource(mCtx.getResources(), R.drawable.me);
			canvas.drawBitmap(bmp, myScreenCoords.x, myScreenCoords.y, paint);
			// canvas.drawText("Here I am...", myScreenCoords.x,
			// myScreenCoords.y, paint);
		}

		return true;
	}
}
*/
